package com.whfc.emp.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.enums.FenceType;
import com.whfc.common.enums.HandleFlag;
import com.whfc.common.exception.BizException;
import com.whfc.common.geometry.GeometryUtil;
import com.whfc.common.geometry.Point;
import com.whfc.common.geometry.Polygon;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.emp.dao.*;
import com.whfc.emp.dto.*;
import com.whfc.emp.dto.openapi.OpenApiEmpWarnDTO;
import com.whfc.emp.entity.AppEmp;
import com.whfc.emp.entity.AppEmpWarn;
import com.whfc.emp.entity.AppEmpWarnRule;
import com.whfc.emp.entity.ClassMeeting;
import com.whfc.emp.enums.AppEmpWarnRuleType;
import com.whfc.emp.enums.WarnType;
import com.whfc.emp.manager.AppEmpDataManager;
import com.whfc.emp.manager.AppEmpWarnRuleManager;
import com.whfc.emp.param.*;
import com.whfc.emp.service.AppEmpWarnService;
import com.whfc.emp.service.AppWorkPlanService;
import com.whfc.emp.service.ClassMeetingService;
import com.whfc.entity.dto.Apply.rep.WorkPlan;
import com.whfc.entity.dto.msg.AppMsgToUserDTO;
import com.whfc.entity.dto.msg.AppWarnMsgRecDTO;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.*;

/**
 * @ClasssName AppEmpWarnServiceImpl
 * @Description 人员报警设置
 * @Author hw
 * @Date 2021/1/5 10:54
 * @Version 1.0
 */
@DubboService(interfaceClass = AppEmpWarnService.class, version = "1.0.0", timeout = 5000)
public class AppEmpWarnServiceImpl implements AppEmpWarnService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AppEmpWarnRuleMapper appEmpWarnRuleMapper;

    @Autowired
    private AppEmpWarnRuleTimeMapper appEmpWarnRuleTimeMapper;

    @Autowired
    private AppEmpWarnRuleUserMapper appEmpWarnRuleUserMapper;

    @Autowired
    private AppEmpWarnRuleChannelMapper appEmpWarnRuleChannelMapper;

    @Autowired
    private AppEmpWarnMapper appEmpWarnMapper;

    @Autowired
    private AppEmpMapper appEmpMapper;

    @Autowired
    private AppEmpWarnRuleManager appEmpWarnRuleManager;

    @Autowired
    private AppEmpWarnRuleFenceMapper empWarnRuleFenceMapper;

    @Autowired
    private AppEmpWarnRuleObjectMapper empWarnRuleObjectMapper;

    @Autowired
    private AppEmpDataManager appEmpDataManager;

    @Autowired
    private ClassMeetingService classMeetingService;

    @Autowired
    private AppWorkPlanService workPlanService;

    @Override
    public PageData<AppWarnRuleDTO> settingList(Integer deptId, Integer pageNum, Integer pageSize, String keyword, Integer ruleType, Integer enableFlag, Integer warnType) {
        logger.info("人员报警规则列表,deptId:{},pageNum:{},pageSize:{},keyword:{},ruleType:{},enableFlag:{},warnType:{}",
                deptId, pageNum, pageSize, keyword, ruleType, enableFlag, warnType);

        if (WarnType.DEVICE.getValue().equals(warnType)) {
            List<AppWarnRuleDTO> deviceWarnList = appEmpWarnRuleMapper.selectRulesByDeptId(deptId, WarnType.DEVICE.getValue());
            if (deviceWarnList.size() <= 0) {
                this.initWarnRule(deptId);
            }
        }

        PageHelper.startPage(pageNum, pageSize);
        List<AppWarnRuleDTO> list = appEmpWarnRuleMapper.selectRulesByDeptId(deptId, warnType);
        PageHelper.clearPage();

        for (AppWarnRuleDTO warnMachSettingDTO : list) {
            Integer ruleId = warnMachSettingDTO.getRuleId();
            // 查找时间段
            List<AppWarnTimeDTO> timeList = appEmpWarnRuleTimeMapper.selectByRuleId(ruleId);
            warnMachSettingDTO.setTimeList(timeList);

            // 查找报警接收人和接收方式
            List<AppMsgToUserDTO> userList = appEmpWarnRuleUserMapper.selectByRuleId(ruleId);
            List<Integer> msgChannelList = appEmpWarnRuleChannelMapper.selectByRuleId(ruleId);
            warnMachSettingDTO.setUserList(userList);
            warnMachSettingDTO.setMsgChannelList(msgChannelList);

            // 如果是电子围栏报警 查找报警区域
            if (AppEmpWarnRuleType.FENCE.value().equals(warnMachSettingDTO.getRuleType())) {
                AppFenceDTO fenceDTO = empWarnRuleFenceMapper.selectByRuleId(ruleId);
                if (fenceDTO != null) {
                    this.translate(fenceDTO);
                    warnMachSettingDTO.setPolygonPointList(fenceDTO.getPolygonPointList());
                    warnMachSettingDTO.setType(fenceDTO.getType());
                    warnMachSettingDTO.setRadius(fenceDTO.getRadius());
                    warnMachSettingDTO.setCenterPoint(fenceDTO.getCenterPoint());
                }
            }

        }
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public void setTime(AppWarnSetTimeParam request) {
        logger.info("人员报警设置报警时间,request:{}", request);
        Integer ruleId = request.getRuleId();
        appEmpWarnRuleTimeMapper.deleteByRuleId(ruleId);
        List<AppWarnTimeDTO> timeList = request.getTimeList();
        if (timeList != null && timeList.size() > 0) {
            for (AppWarnTimeDTO warnTimeDTO : timeList) {
                warnTimeDTO.setRuleId(ruleId);
            }
            appEmpWarnRuleTimeMapper.batchInsert(timeList);
        }
    }

    @Override
    public AppWarnMsgRecDTO userList(Integer ruleId) {
        logger.info("人员报警信息接收人及接收方式,ruleId:{}", ruleId);
        List<AppMsgToUserDTO> userList = appEmpWarnRuleUserMapper.selectByRuleId(ruleId);
        List<Integer> msgChannelList = appEmpWarnRuleChannelMapper.selectByRuleId(ruleId);
        AppWarnMsgRecDTO appWarnMsgRecDTO = new AppWarnMsgRecDTO();
        appWarnMsgRecDTO.setMsgChannelList(msgChannelList);
        appWarnMsgRecDTO.setUserList(userList);
        return appWarnMsgRecDTO;
    }

    @Override
    public void setUser(AppWarnEmpSetUserParam request) {
        logger.info("人员报警设置报警接收人,request:{}", request);
        List<Integer> ruleIdList = request.getRuleIdList();
        for (Integer ruleId : ruleIdList) {
            //消息联系人
            appEmpWarnRuleUserMapper.deleteByRuleId(ruleId);
            List<AppMsgToUserDTO> userIdList = request.getUserList();
            if (userIdList != null && userIdList.size() > 0) {
                for (AppMsgToUserDTO warnUserDTO : userIdList) {
                    warnUserDTO.setRuleId(ruleId);
                }
                appEmpWarnRuleUserMapper.batchInsert(userIdList);
            }

            //消息渠道
            appEmpWarnRuleChannelMapper.deleteByRuleId(ruleId);
            List<Integer> msgChannelList = request.getMsgChannelList();
            if (!msgChannelList.isEmpty()) {
                appEmpWarnRuleChannelMapper.batchInsert(ruleId, msgChannelList);
            }
        }
    }

    @Override
    public PageData<AppWarnEmpRecordDTO> recordList(Integer deptId, Integer pageNum, Integer pageSize, Integer state, Integer ruleType, Date startTime, Date endTime) {
        logger.info("人员报警设置报警接收人,deptId:{},pageNum:{},pageSize:{},state:{},ruleType:{},endTime:{} ",
                deptId, pageNum, pageSize, state, ruleType, endTime);
        PageHelper.startPage(pageNum, pageSize);
        List<AppWarnEmpRecordDTO> list = appEmpWarnMapper.selectByDeptId(deptId, state, ruleType, startTime, endTime);
        for (AppWarnEmpRecordDTO warnEmpRecordDTO : list) {
            Integer empId = warnEmpRecordDTO.getEmpId();
            AppEmp emp = appEmpMapper.selectByPrimaryKey(empId);
            Integer ruleId = warnEmpRecordDTO.getRuleType();
            warnEmpRecordDTO.setEmpName(emp.getEmpName());
            warnEmpRecordDTO.setWorkTypeName(emp.getWorkTypeName());
            warnEmpRecordDTO.setDetail(AppEmpWarnRuleType.parseByValue(ruleId).detail());
            warnEmpRecordDTO.setRuleName(AppEmpWarnRuleType.parseByValue(ruleId).tittle());
            if (emp != null) {
                warnEmpRecordDTO.setEmpName(emp.getEmpName());
                warnEmpRecordDTO.setWorkTypeName(emp.getWorkTypeName());
                warnEmpRecordDTO.setGroupName(emp.getGroupName());
            }
        }
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public AppWarnEmpRecordDetailDTO recordDetail(Integer warnId) {
        logger.info("人员报警详情,warnId:{}", warnId);
        AppWarnEmpRecordDetailDTO warnEmpRecordDetailDTO = new AppWarnEmpRecordDetailDTO();
        AppEmpWarn appWarn = appEmpWarnMapper.selectByPrimaryKey(warnId);
        if (appWarn == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "未找到该报警信息");
        }
        BeanUtils.copyProperties(appWarn, warnEmpRecordDetailDTO);
        warnEmpRecordDetailDTO.setHandleState(appWarn.getState());

        Integer ruleId = appWarn.getRuleId();
        List<AppWarnTimeDTO> appWarnTimeDTOS = appEmpWarnRuleTimeMapper.selectByRuleId(ruleId);
        warnEmpRecordDetailDTO.setTimeList(appWarnTimeDTOS);

        Integer ruleType = appWarn.getRuleType();
        if (AppEmpWarnRuleType.FENCE.value().equals(ruleType)) {
            AppFenceDTO appFenceDTO = empWarnRuleFenceMapper.selectByRuleId(ruleId);
            if (appFenceDTO != null) {
                // 转换空间几何对象
                this.translate(appFenceDTO);
                warnEmpRecordDetailDTO.setType(appFenceDTO.getType());
                warnEmpRecordDetailDTO.setCenterPoint(appFenceDTO.getCenterPoint());
                warnEmpRecordDetailDTO.setPolygonPointList(appFenceDTO.getPolygonPointList());
                warnEmpRecordDetailDTO.setRadius(appFenceDTO.getRadius());
            }
        }

        String triggerObjectId = appWarn.getTriggerObjectId();
        if (AppEmpWarnRuleType.CLASSMEETING_CHECKIN.value().equals(ruleType)){
            ClassMeeting classMeeting = classMeetingService.selectByPrimaryKey(Integer.parseInt(triggerObjectId));
            WorkPlan workPlan = workPlanService.getWorkPlanById(classMeeting.getPlanId());
            Map map = new HashMap();
            map.put("title", "班会人员未认证提醒");
            map.put("classMeetingName", classMeeting.getMeetingName());
            map.put("planName", workPlan.getPlanName());
            map.put("alarm", "有未认证签到人员，请及时查看");
            warnEmpRecordDetailDTO.setExtend(JSON.toJSONString(map));
        } else {
            Integer empId = Integer.parseInt(triggerObjectId);
            //查找人员信息
            AppEmp emp = appEmpMapper.selectByPrimaryKey(empId);
            if (emp == null) {
                throw new BizException(ResultEnum.FAILURE.getCode(), "未找到该报警人员信息");
            }
            // 人员图标处理
            HelmetIconDTO helmetIcon = appEmpDataManager.getHelmetIcon(emp.getColor());
            warnEmpRecordDetailDTO.setIcon(helmetIcon.getIconUrl());

            warnEmpRecordDetailDTO.setWorkTypeName(emp.getWorkTypeName());
            warnEmpRecordDetailDTO.setEmpName(emp.getEmpName());
        }

        return warnEmpRecordDetailDTO;
    }

    @Override
    public void handle(Integer userId, String userName, String phone, AppWarnHandleParam request) {
        logger.info("处理人员报警,userId：{},userName：{},phone：{},request：{}", userId, userName, phone, request);
        AppEmpWarn record = new AppEmpWarn();
        record.setId(request.getWarnId());
        record.setHandleRemark(request.getHandleRemark());
        record.setHandleResult(request.getHandleResult());
        record.setHandleTime(new Date());
        record.setState(HandleFlag.HANDLE.getValue());
        record.setHandleUserId(userId);
        record.setHandleUserName(userName);
        record.setHandleUserPhone(phone);
        appEmpWarnMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public void batchHandle(WarnBatchHandleParam param) throws BizException {
        logger.info("批量处理人员报警记录服务,param:{}", param.toString());
        List<Integer> warnIdList = param.getWarnIdList();
        String handleResult = param.getHandleResult();
        String handleRemark = param.getHandleRemark();
        Integer userId = param.getUserId();
        String userName = param.getUserName();
        String phone = param.getPhone();
        appEmpWarnMapper.batchUpdateState(warnIdList, handleResult, handleRemark, userId, userName, phone);
    }

    @Override
    public void del(WarnBatchDelParam param) throws BizException {
        logger.info("批量删除人员报警记录服务,param:{}", param.toString());
        appEmpWarnMapper.deleteLogicByObjectIds(param.getWarnIdList());
    }

    @Override
    public Integer getWarnNum(List<Integer> deptIds, Date startTime, Date endTime) {
        logger.info("查询时间内报警数,deptIds:{},startTime:{},endTime:{} ", deptIds, startTime, endTime);
        Integer warnNum = appEmpWarnMapper.countWarnNum(deptIds, null, startTime, endTime);
        return warnNum;
    }

    @Override
    public PageData<AppWarnEmpRecordDTO> empWarnList(Integer deptId, Integer pageNum, Integer pageSize, Integer handleState) {
        PageHelper.startPage(pageNum, pageSize);
        List<AppWarnEmpRecordDTO> list = appEmpWarnMapper.selectEmpWarnList(deptId, handleState);
        for (AppWarnEmpRecordDTO warnEmpRecordDTO : list) {
            Integer ruleType = warnEmpRecordDTO.getRuleType();
            Integer empId = warnEmpRecordDTO.getEmpId();
            AppEmp emp = appEmpMapper.selectByPrimaryKey(empId);
            warnEmpRecordDTO.setEmpName(emp.getEmpName());
            warnEmpRecordDTO.setWorkTypeName(emp.getWorkTypeName());
            warnEmpRecordDTO.setDetail(AppEmpWarnRuleType.parseByValue(ruleType).detail());
            warnEmpRecordDTO.setRuleName(AppEmpWarnRuleType.parseByValue(ruleType).tittle());
        }
        PageInfo<AppWarnEmpRecordDTO> pageInfo = PageInfo.of(list);
        return PageUtil.pageData(pageInfo);
    }


    @Override
    public List<OpenApiEmpWarnDTO> getOpenApiEmpWarnList(Integer empId, Date date) throws BizException {
        Date startTime = DateUtil.getDateBegin(date);
        Date endTime = DateUtil.getDateEnd(date);
        return appEmpWarnMapper.selectOpenApiEmpWarnList(empId, startTime, endTime);
    }

    @Override
    public AppWarnEmpRecordNumDTO empWarnNum(Integer deptId, Integer state, Date startTime, Date endTime) {
        List<AppWarnEmpRecordNumDTO> list = appEmpWarnMapper.countWarnTypeNum(deptId, state, startTime, endTime);
        Integer total = list.stream().mapToInt(obj -> obj.getNum()).sum();
        AppWarnEmpRecordNumDTO data = new AppWarnEmpRecordNumDTO();
        data.setTotal(total);
        data.setWarnEmpNum(list);
        return data;
    }

    @Override
    public void enable(AppEmpWarnEnableParam request) {
        appEmpWarnRuleMapper.updateEnableFlagByRuleId(request.getRuleId(), request.getEnableFlag(), request.getGuardianFlag());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settingAdd(AppEmpWarnAddParam param) throws BizException {
        logger.info("添加人员报警规则服务,param:{}", param.toString());
        @NotNull Integer ruleType = param.getRuleType();
        AppEmpWarnRule record = new AppEmpWarnRule();
        record.setDeptId(param.getDeptId());
        record.setName(param.getName());
        record.setRuleType(ruleType);
        record.setWarnType(WarnType.SYSTEM.getValue());
        record.setGuardianFlag(param.getGuardianFlag());
        appEmpWarnRuleMapper.insertSelective(record);
        Integer ruleId = record.getId();

        if (AppEmpWarnRuleType.FENCE.value().equals(ruleType)) {
            this.saveFence(ruleId, param);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settingEdit(AppEmpWarnEditParam param) throws BizException {
        logger.info("编辑人员报警规则服务,param:{}", param.toString());
        @NotNull Integer ruleType = param.getRuleType();
        @NotNull Integer ruleId = param.getRuleId();

        AppEmpWarnRule appEmpWarnRule = appEmpWarnRuleMapper.selectByPrimaryKey(ruleId);
        if (appEmpWarnRule == null) {
            throw new BizException(ResultEnum.NOT_FOUND.getCode(), "未找到该报警规则");
        }

        AppEmpWarnRule record = new AppEmpWarnRule();
        record.setName(param.getName());
        record.setRuleType(ruleType);
        record.setGuardianFlag(param.getGuardianFlag());
        record.setId(ruleId);
        appEmpWarnRuleMapper.updateByPrimaryKeySelective(record);

        if (AppEmpWarnRuleType.FENCE.value().equals(ruleType)) {
            AppEmpWarnAddParam request = new AppEmpWarnAddParam();
            request.setType(param.getType());
            request.setCenterPoint(param.getCenterPoint());
            request.setPolygonPointList(param.getPolygonPointList());
            request.setRadius(param.getRadius());
            request.setDeptId(appEmpWarnRule.getDeptId());
            this.saveFence(ruleId, request);
        }
    }

    @Override
    public void settingDel(Integer ruleId) throws BizException {
        logger.info("删除人员报警规则服务,ruleId:{}", ruleId);
        appEmpWarnRuleMapper.deleteLogic(ruleId);
    }

    @Override
    public ListData<AppEmpDTO> objectList(Integer ruleId, String empName) throws BizException {
        logger.info("查询已有的报警人员服务,ruleId:{},empName:{}", ruleId, empName);
        List<AppEmpDTO> list = empWarnRuleObjectMapper.selectByRuleId(ruleId, empName);
        return new ListData<>(list);
    }

    @Override
    public ListData<AppEmpDTO> getAllObject(Integer ruleId, String empName) throws BizException {
        logger.info("查询可供选择的报警人员服务,ruleId:{},empName:{}", ruleId, empName);
        AppEmpWarnRule empWarnRule = appEmpWarnRuleMapper.selectByPrimaryKey(ruleId);
        if (empWarnRule == null) {
            throw new BizException(ResultEnum.NOT_FOUND.getCode(), "未找到该报警规则");
        }
        Integer ruleType = empWarnRule.getRuleType();
        Integer deptId = empWarnRule.getDeptId();
        List<AppEmpDTO> list = empWarnRuleObjectMapper.selectAvailableEmp(deptId, ruleType, empName);
        return new ListData<>(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void objectAdd(EmpWarnObjectAddParam param) throws BizException {
        logger.info("添加报警人员服务,param :{}", param.toString());
        List<Integer> empIdList = param.getEmpIdList();
        @NotNull Integer ruleId = param.getRuleId();
        empWarnRuleObjectMapper.deleteLogicByRuleId(ruleId);
        if (empIdList != null && empIdList.size() > 0) {
            // 批量插入
            empWarnRuleObjectMapper.batchInsert(ruleId, empIdList);
        }
    }

    @Override
    public List<AppWarnEmpRecordDTO> getNewList(Integer deptId) {
        List<AppWarnEmpRecordDTO> list = appEmpWarnMapper.selectNewEmpWarnList(deptId);
        for (AppWarnEmpRecordDTO warnEmpRecordDTO : list) {
            Integer ruleType = warnEmpRecordDTO.getRuleType();
            Integer empId = warnEmpRecordDTO.getEmpId();
            AppEmp emp = appEmpMapper.selectByPrimaryKey(empId);
            warnEmpRecordDTO.setEmpName(emp.getEmpName());
            warnEmpRecordDTO.setWorkTypeName(emp.getWorkTypeName());
            warnEmpRecordDTO.setDetail(AppEmpWarnRuleType.parseByValue(ruleType).detail());
            warnEmpRecordDTO.setRuleName(AppEmpWarnRuleType.parseByValue(ruleType).tittle());
        }
        return list;
    }

    /**
     * 保存电子围栏
     *
     * @param ruleId
     * @param param
     */
    private void saveFence(Integer ruleId, AppEmpWarnAddParam param) {
        Integer type = param.getType();
        String polygon = null;
        String center = null;
        // 多边形
        if (FenceType.POLYGON.value().equals(type)) {
            List<Point> polygonPointList = param.getPolygonPointList();
            if (polygonPointList == null || polygonPointList.size() < 3) {
                throw new BizException(ResultEnum.FAILURE.getCode(), "多边形参数不正确!");
            }
            // 首位相连
            polygonPointList.add(polygonPointList.get(0));
            polygon = GeometryUtil.encodePolygon(new Polygon(polygonPointList));
        }
        // 圆形
        else if (FenceType.CIRCLE.value().equals(type)) {
            Point centerPoint = param.getCenterPoint();
            Double radius = param.getRadius();
            if (centerPoint == null || radius == null) {
                throw new BizException(ResultEnum.FAILURE.getCode(), "圆形参数不正确!");
            }
            center = GeometryUtil.encodePoint(centerPoint);
        }

        empWarnRuleFenceMapper.deleteLogicByRuleId(ruleId);

        param.setRuleId(ruleId);
        param.setPolygon(polygon);
        param.setCenter(center);

        empWarnRuleFenceMapper.insertSelectiveByParam(param);

    }

    private void initWarnRule(Integer deptId) {
        List<AppEmpWarnRule> list = new ArrayList<>();
        AppEmpWarnRuleType[] warnRuleTypes = AppEmpWarnRuleType.values();
        for (AppEmpWarnRuleType empWarnRuleType : warnRuleTypes) {
            AppEmpWarnRule record = new AppEmpWarnRule();
            record.setDeptId(deptId);
            record.setName(empWarnRuleType.tittle());
            record.setRuleType(empWarnRuleType.value());
            list.add(record);
        }
        appEmpWarnRuleMapper.batchInsert(list);
    }

    /**
     * 转换空间几何对象
     *
     * @param appFenceDTO
     */
    private void translate(AppFenceDTO appFenceDTO) {
        if (FenceType.POLYGON.value().equals(appFenceDTO.getType())) {
            Polygon polygon = GeometryUtil.decodePolygon(appFenceDTO.getPolygon());
            appFenceDTO.setPolygonPointList(polygon.getPointList());
        }
        //圆形
        if (FenceType.CIRCLE.value().equals(appFenceDTO.getType())) {
            Point point = GeometryUtil.decodePoint(appFenceDTO.getCenter());
            appFenceDTO.setCenterPoint(point);
        }
    }
}